package com.zym.framework.combobox;

import com.zym.application.utils.StringUtils;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

import java.util.List;

/**
 * QQ 165149324
 * 臧英明
 *
 * @author
 * @create 2021-03-03
 */
public class AutoComplete <T> implements EventHandler<KeyEvent> {

    private ComboBox comboBox;
    private StringBuilder sb;
    private ObservableList<T> data;
    private boolean moveCaretToPos = false;
    private int caretPos;
    private boolean mapQuery = false;

    public void setMapQuery(boolean mapQuery) {
        this.mapQuery = mapQuery;
    }

    public AutoComplete(final ComboBox comboBox) {
        this.comboBox = comboBox;
        sb = new StringBuilder();
        data = comboBox.getItems();
        this.comboBox.setEditable(true);
        this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent t) {
                comboBox.hide();
            }
        });
        this.comboBox.setOnKeyReleased(AutoComplete.this);
    }
    public void setPromptText(String text){
        comboBox.setPromptText(text);
    }
    public void setOnKeyPressed(EventHandler<KeyEvent> eventEventHandler) {
        this.comboBox.setOnKeyPressed(eventEventHandler);
    }
    public void hide(){
        this.comboBox.hide();
    }
    public void setChangeListener(ChangeListener changeListener){
        this.comboBox.focusedProperty().addListener(changeListener);
    }
    public void setOnKeyReleased( EventHandler<? super KeyEvent> value){
        this.comboBox.setOnKeyReleased(value);
    }
    public String getText(){
       return comboBox.getEditor().getText();
    }

    @Override
    public void handle(KeyEvent event) {

        if(event.getCode() == KeyCode.UP) {
            caretPos = -1;
            moveCaret(comboBox.getEditor().getText().length());
            return;
        } else if(event.getCode() == KeyCode.DOWN) {
            if(!comboBox.isShowing()) {
                comboBox.show();
            }
            caretPos = -1;
            moveCaret(comboBox.getEditor().getText().length());
            return;
        } else if(event.getCode() == KeyCode.BACK_SPACE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        } else if(event.getCode() == KeyCode.DELETE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        }

        if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
                || event.isControlDown() || event.getCode() == KeyCode.HOME
                || event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
            return;
        }

        ObservableList list = FXCollections.observableArrayList();
        for (int i=0; i<data.size(); i++) {
            if(mapQuery){
                data.get(i);
                if(data.get(i) != null && StringUtils.isNotEmpty(data.get(i).toString()) && !data.get(i).toString().equals("[]")){
                    list.add(data.get(i));
                }
            }else {
                if(data.get(i).toString().toLowerCase().startsWith(
                        AutoComplete.this.comboBox
                                .getEditor().getText().toLowerCase())) {
                    list.add(data.get(i));
                }
            }
        }
        String t = comboBox.getEditor().getText();

        comboBox.setItems(list);
        comboBox.getEditor().setText(t);
        if(!moveCaretToPos) {
            caretPos = -1;
        }
        moveCaret(t.length());
        if(!list.isEmpty()) {
            comboBox.show();
        }
    }

    private void moveCaret(int textLength) {
        if(caretPos == -1) {
            comboBox.getEditor().positionCaret(textLength);
        } else {
            comboBox.getEditor().positionCaret(caretPos);
        }
        moveCaretToPos = false;
    }

    public void setData(List<T> datas) {
        this.data.clear();
        this.data.addAll(datas);
    }
}